﻿using System;
using System.Collections.Generic;
using NUnit.Framework;
using NUnit.Mocks;

using System.Configuration;
using Theoreme.Samples.UnitTesting.Mocks.BLL;

namespace Theoreme.Samples.UnitTesting.Mocks.Tests
{

    [TestFixture]
    public class Test_PersonService
    {
        
        // variable used to choose between dynamic Mock objects and a real implementation..
        private bool _useMocks = false;
        
        
        // The dynamic mock proxy that we will use to implement IPersonRepository
        private DynamicMock personRepositoryMock;


        // Set up some testing data
        private Person          onePerson        = new Person("1", "Wendy", "Whiner");
        private Person          secondPerson     = new Person("2", "Aaron", "Adams");
        private List<Person>    peopleList;


        [SetUp]
        public void TestInit()
        {
            peopleList = new List<Person>();
            peopleList.Add(onePerson);
            peopleList.Add(secondPerson);


            // Construct a Mock Object of the IPersonRepository Interface
            personRepositoryMock = new DynamicMock(typeof(IPersonRepository));

            // Set the choice between using the "real" object (RealPersonRepository) or 
            // the mock object, by reading a key in the app.config file of the test project.
            setMockContextFromConfigFile();
        }

        /// <summary>
        /// Sets the mock context from config file.
        /// </summary>
        private void setMockContextFromConfigFile()
        {
            string useMock = ConfigurationManager.AppSettings["UseMocks"];

            _useMocks = Convert.ToBoolean(useMock);
        }
    

        private PersonService GetPersonService()
        {
            PersonService service = null;

            if (_useMocks)
            {
                service = new PersonService((IPersonRepository)personRepositoryMock.MockInstance);
            }
            else
            {
                service = new PersonService(new RealPersonRepository());
            }
            
            return service;
        }


        [Test]
        public void TestGetAllPeople()
        {
            // Tell that mock object when the "GetPeople" method is 
            // called to return a predefined list of people
            personRepositoryMock.ExpectAndReturn("GetPeople", peopleList);

            // Construct a Person service with the Mock IPersonRepository
            PersonService service = GetPersonService();

            // Call methods and assert tests
            Assert.AreEqual(2, service.GetAllPeople().Count);
        }

       
        
        [Test]
        public void TestGetAllPeopleSorted()
        {
            // Tell that mock object when the "GetPeople" method is called to 
            // return a predefined list of people
            personRepositoryMock.ExpectAndReturn("GetPeople", peopleList);

            PersonService service = GetPersonService();
            
            // This method really has "business logic" in it - the sorting of people
            List<Person> people = service.GetAllPeopleSorted();
            
            Assert.IsNotNull(people);
            Assert.AreEqual(2, people.Count);
            
            // Make sure the first person returned is the correct one
            Person p = people[0];
            Assert.AreEqual("Adams", p.LastName);
        }
        
        
        [Test]
        public void TestGetSinglePersonWithValidId()
        {
            // Tell that mock object when the "GetPerson" method is called to 
            // return a predefined Person
            personRepositoryMock.ExpectAndReturn("GetPersonById", onePerson, "1");

            PersonService service = GetPersonService();

            Person p = service.GetPerson("1");
            
            Assert.IsNotNull(p);
            Assert.AreEqual(p.Id, "1");
        }

        [Test]
        public void TestGetSinglePersonWithInvalidId()
        {
            // Tell that mock object when the "GetPersonById" is called with a null
            // value to throw an ArgumentException
            personRepositoryMock.ExpectAndThrow("GetPersonById",new ArgumentException("Invalid person id."), null);

            PersonService service = GetPersonService();

            // The only way to get null is if the underlying IPersonRepository threw an ArgumentException
            Assert.IsNull(service.GetPerson(null));
        }
    }
}